<!-- 上传组件 -->
<script setup lang='ts'>
  import { reactive, ref, watch } from 'vue'
  import { useCurrentInstance } from '@/common/utils/methods'
  import { formatImgUrl } from '@/common/utils/utils'
  import type { ElUpload, ElImage } from 'element-plus'
  const { $message, $axios } = useCurrentInstance()

  const data = reactive({ 
    imageUrl: '',
    imageLoading: false 
  });

  const props = defineProps<{ 
    imageUrl: string
  }>()

  const emit = defineEmits<{
    (e: 'update:imageUrl', url: string): void
  }>()

  watch(() => props.imageUrl, (url) => {
    data.imageUrl = url;
  })

  // 上传校验
  const beforeUpload = (file: File) => {
    const isJPG = ['image/jpeg', 'image/png', 'image/jpg'].includes(file.type);
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isJPG) {
      $message.error('只能上传jpg或png格式图片！')
      return false;
    }
    if (!isLt2M) {
      $message.error('图片大小不能超过2MB!')
      return false;
    }
    return true;
  }

  // 上传图片
  const UploadFilled = async (file: File) => {
    data.imageLoading = true;
    try {
      // 获取验证签名
      const userDir = 'erp/exam'; // 指定上传的文件夹
      const tickers = await $axios.post('/common.core.api/common/oss/batchTicker', {
        userDir,
        applyId: 0,
        uploadSize: 1
      })

      // 上传文件
      const { host, userData, policy, accessId, signature, keys } = tickers.data[0];

      // 获取文件名
      const suffix = file.name.split('.').pop();
      const key = userDir + '/' + keys[0] + '.' + suffix;

      // 生成上传文件请求体
      let formData = new FormData();
      formData.append('key', key);
      formData.append('policy', policy);
      formData.append('OSSAccessKeyId', accessId);
      formData.append('success_action_status', '200');
      formData.append('signature', signature);
      formData.append('file', file, file.name);

      // 开始上传，此接口无返回值
      await $axios.post(host, formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        timeout: 10 * 60 * 10000
      })

      // 获取上传的图片地址
      const imgRes = await $axios.post('/common.core.api/common/oss/callback',{
        upload: [{ key: keys[0], md5: '', suffix}],
        userData: userData
      })
      data.imageLoading = false;
      emit('update:imageUrl', imgRes.data[0].url);
      return imgRes.data[0].url;
    } catch(e){
      $message.error('上传失败，请重试');
      data.imageLoading = false;
      return;
    }
    
  }

  // 自定义上传
  const customUpload = async (e: any) => {
    // 校验文件类型和大小
    const checkResult = beforeUpload(e.file);

    // 通过校验则上传
    if (!checkResult) return;
    const imageUrl = await UploadFilled(e.file);
    if (imageUrl) {
      data.imageUrl = imageUrl
    }
  }

  // 删除图片
  const imageUploader = ref<InstanceType<typeof ElUpload>>();
  const deleteImage = () => {
    data.imageUrl = '';
    imageUploader.value?.clearFiles();
    emit('update:imageUrl', '');
  }

  // 查看图片
  const imageView = ref<InstanceType<typeof ElImage>>();
  const imagePreview = () => {
    imageView.value?.clickHandler()
  }
</script>

<template>
  <div>
    <div class="imageList" v-if="data.imageUrl">
      <el-image
        ref="imageView"
        class="image"
        fit="none"
        :src="formatImgUrl(data.imageUrl)"
        :preview-src-list="[formatImgUrl(data.imageUrl)]"
        :initial-index="1"
      >
      </el-image>
      
      <div class="image-cover">
        <div class="image-fn">
          <span @click="imagePreview" style="margin-right: 40px;">
            <el-icon color="#fff"><zoom-in /></el-icon>
          </span>
          <span @click="deleteImage">
            <el-icon color="#fff"><delete /></el-icon>
          </span>
        </div>
      </div>
    </div>
    <el-upload
      v-else
      ref="imageUploader"
      class="uploader"
      action=""
      :http-request="customUpload"
      :show-file-list="false"
    >
      <el-icon class="uploader-icon" v-loading="data.imageLoading"><plus /></el-icon>
    </el-upload>
  </div>
</template>

<style scoped>
  :deep(.uploader .el-upload) {
    display: inline-block;
    text-align: center;
    outline: none;
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .image, .imageList {
    width: 178px;
    height: 178px;
  }
  .imageList {
    position: relative;
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
  }
  .imageList:hover .image-cover {
    display: block;
  }
  .image-cover {
    display: none;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background: rgba(0,0,0,0.4);
    cursor: pointer;
  }
  .image-fn {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
  }
  .uploader-icon {
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    text-align: center;
  }
</style>